﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SharepointSolutionInstaller.Utils;
using Microsoft.SharePoint;
using SharepointSolutionInstaller.Resources;
using Microsoft.SharePoint.Administration;
using System.IO;
using System.Collections.ObjectModel;
using System.Data.SqlClient;
using System.Security;
using System.Threading;
using SharepointSolutionInstaller.Utils.SolutionDeployment;
using SharepointSolutionInstaller.Utils.Configuration;
using SharepointSolutionInstaller.Utils.Log;

namespace SharepointSolutionInstaller.Views
{
    public partial class InstallProcess : InstallerControl
    {
        #region Members
        private static readonly Logger log = Logger.messageCollector();
        private static readonly TimeSpan JobTimeout = TimeSpan.FromMinutes(15);
        private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
        private List<Command> executeCommands;
        private List<Command> rollbackCommands;
        private int nextCommand;
        private bool completed;
        private bool requestCancel;
        private int errors;
        private int rollbackErrors;
        #endregion

        public InstallProcess()
        {
            InitializeComponent();
            errorPictureBox.Visible = false;
            errorDetailsTextBox.Visible = false;

            this.Load += new EventHandler(InstallProcessControl_Load);
        }

        #region Event Handlers

        private void InstallProcessControl_Load(object sender, EventArgs e)
        {
            SetTitles();
            Form.btnPrevious.Enabled = false;
            Form.btnNext.Enabled = false;
        }

        private void TimerEventInstall(Object myObject, EventArgs myEventArgs)
        {
            timer.Stop();

            if (requestCancel)
            {
                descriptionLabel.Text = Resources.CommonUIStrings.descriptionLabelTextOperationCanceled;
                InitiateRollback();
            }

            else if (nextCommand < executeCommands.Count)
            {
                try
                {
                    Command command = executeCommands[nextCommand];
                    if (command.Execute())
                    {
                        nextCommand++;
                        progressBar.PerformStep();

                        if (nextCommand < executeCommands.Count)
                        {
                            descriptionLabel.Text = executeCommands[nextCommand].Description;
                        }
                    }
                    timer.Start();
                }
                catch (Exception ex)
                {
                    log.Error(CommonUIStrings.logError);
                    log.Error(ex.Message, ex);

                    errors++;
                    errorPictureBox.Visible = true;
                    errorDetailsTextBox.Visible = true;
                    errorDetailsTextBox.Text = ex.Message;

                    descriptionLabel.Text = Resources.CommonUIStrings.descriptionLabelTextErrorsDetected;
                    InitiateRollback();
                }
            }

            else
            {
                descriptionLabel.Text = Resources.CommonUIStrings.descriptionLabelTextSuccess;
                HandleCompletion();
            }
        }

        private void TimerEventRollback(Object myObject, EventArgs myEventArgs)
        {
            timer.Stop();

            if (nextCommand < rollbackCommands.Count)
            {
                try
                {
                    Command command = rollbackCommands[nextCommand];
                    if (command.Rollback())
                    {
                        nextCommand++;
                        progressBar.PerformStep();
                    }
                }
                catch (Exception ex)
                {
                    log.Error(CommonUIStrings.logError);
                    log.Error(ex.Message, ex);

                    rollbackErrors++;
                    nextCommand++;
                    progressBar.PerformStep();
                }

                timer.Start();
            }

            else
            {
                if (rollbackErrors == 0)
                {
                    descriptionLabel.Text = Resources.CommonUIStrings.descriptionLabelTextRollbackSuccess;
                }
                else
                {
                    descriptionLabel.Text = string.Format(Resources.CommonUIStrings.descriptionLabelTextRollbackError, rollbackErrors);
                }

                HandleCompletion();
            }
        }

        #endregion

        #region Protected Methods

        protected internal override void RequestCancel()
        {
            if (completed)
            {
                base.RequestCancel();
            }
            else
            {
                requestCancel = true;
                Form.btnCancel.Enabled = false;
            }
        }

        protected internal override void Open(InstallOptions options)
        {
            executeCommands = new List<Command>();
            rollbackCommands = new List<Command>();
            nextCommand = 0;
            SPFeatureScope featureScope = InstallConfiguration.FeatureScope;
            DeactivateSiteCollectionFeatureCommand deactivateSiteCollectionFeatureCommand = null;

            switch (Form.operation)
            {
                case InstallOperation.Install:
                    Install(featureScope, options);
                    break;

                case InstallOperation.Upgrade:
                    Upgrade(featureScope, deactivateSiteCollectionFeatureCommand);
                    break;

                case InstallOperation.Repair:
                    Repair(featureScope, deactivateSiteCollectionFeatureCommand);
                    break;

                case InstallOperation.Uninstall:
                    Uninstall(featureScope);
                    break;
            }

            progressBar.Maximum = executeCommands.Count;
            descriptionLabel.Text = executeCommands[0].Description;

            timer.Interval = 1000;
            timer.Tick += new EventHandler(TimerEventInstall);
            timer.Start();
        }






        #endregion

        #region Private Methods

        private void HandleCompletion()
        {
            completed = true;

            Form.btnNext.Enabled = true;
            Form.btnCancel.Text = CommonUIStrings.abortButtonText;
            Form.btnCancel.Enabled = true;

            DetailsView nextControl = new DetailsView();

            foreach (string message in log.Messages)
            {
                nextControl.Details += message + "\r\n";
            }

            switch (Form.operation)
            {
                case InstallOperation.Install:
                    nextControl.Title = errors == 0 ? CommonUIStrings.installSuccess : CommonUIStrings.installError;
                    break;

                case InstallOperation.Upgrade:
                    nextControl.Title = errors == 0 ? CommonUIStrings.upgradeSuccess : CommonUIStrings.upgradeError;
                    break;

                case InstallOperation.Repair:
                    nextControl.Title = errors == 0 ? CommonUIStrings.repairSuccess : CommonUIStrings.repairError;
                    break;

                case InstallOperation.Uninstall:
                    nextControl.Title = errors == 0 ? CommonUIStrings.uninstallSuccess : CommonUIStrings.uninstallError;
                    break;
            }

            Form.contentControls.Add(nextControl);
        }

        private void InitiateRollback()
        {
            Form.btnCancel.Enabled = false;

            progressBar.Maximum = rollbackCommands.Count;
            progressBar.Value = rollbackCommands.Count;
            nextCommand = 0;
            rollbackErrors = 0;
            progressBar.Step = -1;

            //
            // Create and start new timer.
            //
            timer = new System.Windows.Forms.Timer();
            timer.Interval = 1000;
            timer.Tick += new EventHandler(TimerEventRollback);
            timer.Start();
        }

        private bool IsSolutionRenamed()
        {
            SPFarm farm = SPFarm.Local;
            SPSolution solution = farm.Solutions[InstallConfiguration.SolutionId];
            if (solution == null) return false;

            FileInfo solutionFileInfo = new FileInfo(InstallConfiguration.SolutionFile);

            return !solution.Name.Equals(solutionFileInfo.Name, StringComparison.OrdinalIgnoreCase);
        }

        private Collection<SPWebApplication> GetDeployedApplications()
        {
            SPFarm farm = SPFarm.Local;
            SPSolution solution = farm.Solutions[InstallConfiguration.SolutionId];
            if (solution.ContainsWebApplicationResource)
            {
                return solution.DeployedWebApplications;
            }
            return null;
        }

        private void SetTitles()
        {
            switch (Form.operation)
            {
                case InstallOperation.Install:
                    Form.SetTitle(CommonUIStrings.installTitle);
                    Form.SetSubTitle(InstallConfiguration.FormatString(CommonUIStrings.installSubTitle));
                    break;

                case InstallOperation.Upgrade:
                    Form.SetTitle(CommonUIStrings.upgradeTitle);
                    Form.SetSubTitle(InstallConfiguration.FormatString(CommonUIStrings.upgradeSubTitle));
                    break;

                case InstallOperation.Repair:
                    Form.SetTitle(CommonUIStrings.repairTitle);
                    Form.SetSubTitle(InstallConfiguration.FormatString(CommonUIStrings.repairSubTitle));
                    break;

                case InstallOperation.Uninstall:
                    Form.SetTitle(CommonUIStrings.uninstallTitle);
                    Form.SetSubTitle(InstallConfiguration.FormatString(CommonUIStrings.uninstallSubTitle));
                    break;
            }
        }

        private void Install(SPFeatureScope featureScope, InstallOptions options)
        {
            executeCommands.Add(new AddSolutionCommand(this, InstallConfiguration.SolutionFile, InstallConfiguration.SolutionId));
            executeCommands.Add(new CreateDeploymentJobCommand(this, options.WebApplicationTargets, InstallConfiguration.SolutionId,InstallConfiguration.SolutionTitle));
            executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionDeployment, InstallConfiguration.SolutionId));
            if (installOfficeSolution)
            {
                executeCommands.Add(new AddSolutionCommand(this, InstallConfiguration.OfficeSolutionFile, InstallConfiguration.OfficeSolutionId));
                executeCommands.Add(new CreateDeploymentJobCommand(this, options.WebApplicationTargets, InstallConfiguration.OfficeSolutionId, InstallConfiguration.OfficeSolutionTitle));
                executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionDeployment, InstallConfiguration.OfficeSolutionId));
            }
            if (featureScope == SPFeatureScope.Farm)
            {
                executeCommands.Add(new ActivateFarmFeatureCommand(this, InstallConfiguration.FeatureId));
            }
            else if (featureScope == SPFeatureScope.Site)
            {
                executeCommands.Add(new ActivateSiteCollectionFeatureCommand(this, options.SiteCollectionTargets, InstallConfiguration.FeatureId));
            }
            if (installOfficeSolution)
                executeCommands.Add(new ActivateFarmFeatureCommand(this, InstallConfiguration.OfficeFarmFeatureId));
            executeCommands.Add(new RegisterVersionNumberCommand(this));

            for (int i = executeCommands.Count - 1; i <= 0; i--)
            {
                rollbackCommands.Add(executeCommands[i]);
            }
        }

        private void Upgrade(SPFeatureScope featureScope, DeactivateSiteCollectionFeatureCommand deactivateSiteCollectionFeatureCommand)
        {
            if (featureScope == SPFeatureScope.Farm)
            {
                executeCommands.Add(new DeactivateFarmFeatureCommand(this, InstallConfiguration.FeatureId));
            }
            else if (featureScope == SPFeatureScope.Site)
            {
                deactivateSiteCollectionFeatureCommand = new DeactivateSiteCollectionFeatureCommand(this, InstallConfiguration.SolutionId, InstallConfiguration.FeatureId);
                executeCommands.Add(deactivateSiteCollectionFeatureCommand);
            }
            if (!IsSolutionRenamed())
            {
                executeCommands.Add(new CreateUpgradeJobCommand(this, InstallConfiguration.SolutionFile, InstallConfiguration.SolutionId));
                executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionUpgrade, InstallConfiguration.SolutionId));
            }
            else
            {
                executeCommands.Add(new CreateRetractionJobCommand(this, InstallConfiguration.SolutionId));
                executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionRetraction, InstallConfiguration.SolutionId));
                executeCommands.Add(new RemoveSolutionCommand(this, InstallConfiguration.SolutionId));
                executeCommands.Add(new AddSolutionCommand(this, InstallConfiguration.SolutionFile, InstallConfiguration.SolutionId));
                executeCommands.Add(new CreateDeploymentJobCommand(this, GetDeployedApplications(), InstallConfiguration.SolutionId, InstallConfiguration.SolutionTitle));
                executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionDeployment, InstallConfiguration.SolutionId));
            }
            if (featureScope == SPFeatureScope.Farm)
            {
                executeCommands.Add(new ActivateFarmFeatureCommand(this, InstallConfiguration.FeatureId));
            }
            if (featureScope == SPFeatureScope.Site)
            {
                executeCommands.Add(new ActivateSiteCollectionFeatureCommand(this, deactivateSiteCollectionFeatureCommand.DeactivatedSiteCollections, InstallConfiguration.FeatureId));
            }
            executeCommands.Add(new RegisterVersionNumberCommand(this));
        }

        private void Repair(SPFeatureScope featureScope, DeactivateSiteCollectionFeatureCommand deactivateSiteCollectionFeatureCommand)
        {
            if (featureScope == SPFeatureScope.Farm)
            {
                executeCommands.Add(new DeactivateFarmFeatureCommand(this, InstallConfiguration.FeatureId));
            }
            if (featureScope == SPFeatureScope.Site)
            {
                deactivateSiteCollectionFeatureCommand = new DeactivateSiteCollectionFeatureCommand(this, InstallConfiguration.SolutionId, InstallConfiguration.FeatureId);
                executeCommands.Add(deactivateSiteCollectionFeatureCommand);
            }
            executeCommands.Add(new CreateRetractionJobCommand(this, InstallConfiguration.SolutionId));
            executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionRetraction, InstallConfiguration.SolutionId));
            executeCommands.Add(new RemoveSolutionCommand(this, InstallConfiguration.SolutionId));
            executeCommands.Add(new AddSolutionCommand(this, InstallConfiguration.SolutionFile, InstallConfiguration.SolutionId));
            executeCommands.Add(new CreateDeploymentJobCommand(this, GetDeployedApplications(), InstallConfiguration.SolutionId, InstallConfiguration.SolutionTitle));
            executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionDeployment, InstallConfiguration.SolutionId));
            if (featureScope == SPFeatureScope.Farm)
            {
                executeCommands.Add(new ActivateFarmFeatureCommand(this, InstallConfiguration.FeatureId));
            }
            if (featureScope == SPFeatureScope.Site)
            {
                executeCommands.Add(new ActivateSiteCollectionFeatureCommand(this, deactivateSiteCollectionFeatureCommand.DeactivatedSiteCollections, InstallConfiguration.FeatureId));
            }
            executeCommands.Add(new RegisterVersionNumberCommand(this));

            if (isOfficeSolutionInstalled)
            {
                //desactive the office feature
                executeCommands.Add(new DeactivateFarmFeatureCommand(this, InstallConfiguration.OfficeFarmFeatureId));
                //retract office solution
                executeCommands.Add(new CreateRetractionJobCommand(this, InstallConfiguration.OfficeSolutionId));

                executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionRetraction, InstallConfiguration.OfficeSolutionId));
                executeCommands.Add(new RemoveSolutionCommand(this, InstallConfiguration.OfficeSolutionId));
                executeCommands.Add(new AddSolutionCommand(this, InstallConfiguration.OfficeSolutionFile, InstallConfiguration.OfficeSolutionId));
                executeCommands.Add(new CreateDeploymentJobCommand(this, GetDeployedApplications(), InstallConfiguration.OfficeSolutionId, InstallConfiguration.OfficeSolutionTitle));
                executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionDeployment, InstallConfiguration.OfficeSolutionId));
                executeCommands.Add(new ActivateFarmFeatureCommand(this, InstallConfiguration.OfficeFarmFeatureId));
            }


        }

        private void Uninstall(SPFeatureScope featureScope)
        {
            if (featureScope == SPFeatureScope.Farm)
            {
                executeCommands.Add(new DeactivateFarmFeatureCommand(this, InstallConfiguration.FeatureId));
            }
            if (featureScope == SPFeatureScope.Site)
            {
                executeCommands.Add(new DeactivateSiteCollectionFeatureCommand(this, InstallConfiguration.SolutionId, InstallConfiguration.FeatureId));
            }
            //delete sharepoint list security solution
            executeCommands.Add(new CreateRetractionJobCommand(this, InstallConfiguration.SolutionId));
            executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionRetraction, InstallConfiguration.SolutionId));
            executeCommands.Add(new RemoveSolutionCommand(this, InstallConfiguration.SolutionId));
            executeCommands.Add(new UnregisterVersionNumberCommand(this));
            if (isOfficeSolutionInstalled)
            {
                //desactive office feature
                executeCommands.Add(new DeactivateFarmFeatureCommand(this, InstallConfiguration.OfficeFarmFeatureId));
                //delete office solution
                executeCommands.Add(new CreateRetractionJobCommand(this, InstallConfiguration.OfficeSolutionId));
                executeCommands.Add(new WaitForJobCompletionCommand(this, CommonUIStrings.waitForSolutionRetraction, InstallConfiguration.OfficeSolutionId));
                executeCommands.Add(new RemoveSolutionCommand(this, InstallConfiguration.OfficeSolutionId));
            }
        }

        #endregion
    }
}
